/*
 * @Author: MingYuCheung
 * @Date: 2025-11-05
 * @FilePath: \ToonaVisualize\crates\kernel\src\scene_graph\bounding_volume.rs
 * @Description: 包围体计算和管理
 */
use tvk_base::math::glam::{Mat4, Vec3};

/// 轴对齐包围盒（AABB）
#[derive(Debug, Clone, Copy)]
pub struct AABB {
    pub min: Vec3,
    pub max: Vec3,
}

impl AABB {
    /// 创建新的AABB
    pub fn new(min: Vec3, max: Vec3) -> Self {
        Self { min, max }
    }

    /// 创建空的AABB
    pub fn empty() -> Self {
        Self {
            min: Vec3::splat(f32::INFINITY),
            max: Vec3::splat(f32::NEG_INFINITY),
        }
    }

    /// 从点集合创建AABB
    pub fn from_points(points: &[Vec3]) -> Self {
        if points.is_empty() {
            return Self::empty();
        }

        let mut min = points[0];
        let mut max = points[0];

        for point in &points[1..] {
            min = min.min(*point);
            max = max.max(*point);
        }

        Self::new(min, max)
    }

    /// 获取AABB的中心
    pub fn center(&self) -> Vec3 {
        (self.min + self.max) * 0.5
    }

    /// 获取AABB的大小
    pub fn size(&self) -> Vec3 {
        self.max - self.min
    }

    /// 获取AABB的半径
    pub fn radius(&self) -> f32 {
        self.size().length() * 0.5
    }

    /// 检查点是否在AABB内
    pub fn contains_point(&self, point: Vec3) -> bool {
        point.x >= self.min.x
            && point.x <= self.max.x
            && point.y >= self.min.y
            && point.y <= self.max.y
            && point.z >= self.min.z
            && point.z <= self.max.z
    }

    /// 检查两个AABB是否相交
    pub fn intersects(&self, other: &AABB) -> bool {
        self.min.x <= other.max.x
            && self.max.x >= other.min.x
            && self.min.y <= other.max.y
            && self.max.y >= other.min.y
            && self.min.z <= other.max.z
            && self.max.z >= other.min.z
    }

    /// 合并两个AABB
    pub fn merge(&mut self, other: &AABB) {
        self.min = self.min.min(other.min);
        self.max = self.max.max(other.max);
    }

    /// 返回两个AABB的合并结果
    pub fn merged(&self, other: &AABB) -> Self {
        Self {
            min: self.min.min(other.min),
            max: self.max.max(other.max),
        }
    }

    /// 使用变换矩阵变换AABB
    pub fn transform(&self, matrix: &Mat4) -> Self {
        let corners = [
            self.min,
            Vec3::new(self.max.x, self.min.y, self.min.z),
            Vec3::new(self.min.x, self.max.y, self.min.z),
            Vec3::new(self.max.x, self.max.y, self.min.z),
            Vec3::new(self.min.x, self.min.y, self.max.z),
            Vec3::new(self.max.x, self.min.y, self.max.z),
            Vec3::new(self.min.x, self.max.y, self.max.z),
            self.max,
        ];

        // 变换所有角点
        let transformed_corners: Vec<_> = corners
            .iter()
            .map(|&corner| (*matrix * corner.extend(1.0)).truncate())
            .collect();

        Self::from_points(&transformed_corners)
    }

    /// 获取AABB的所有角点
    pub fn corners(&self) -> [Vec3; 8] {
        [
            self.min,
            Vec3::new(self.max.x, self.min.y, self.min.z),
            Vec3::new(self.min.x, self.max.y, self.min.z),
            Vec3::new(self.max.x, self.max.y, self.min.z),
            Vec3::new(self.min.x, self.min.y, self.max.z),
            Vec3::new(self.max.x, self.min.y, self.max.z),
            Vec3::new(self.min.x, self.max.y, self.max.z),
            self.max,
        ]
    }
}

/// 包围球
#[derive(Debug, Clone, Copy)]
pub struct BoundingSphere {
    pub center: Vec3,
    pub radius: f32,
}

impl BoundingSphere {
    /// 创建新的包围球
    pub fn new(center: Vec3, radius: f32) -> Self {
        Self { center, radius }
    }

    /// 从AABB创建包围球
    pub fn from_aabb(aabb: &AABB) -> Self {
        let center = aabb.center();
        let radius = aabb.radius();
        Self { center, radius }
    }

    /// 从点集合创建包围球
    pub fn from_points(points: &[Vec3]) -> Self {
        let aabb = AABB::from_points(points);
        Self::from_aabb(&aabb)
    }

    /// 检查点是否在包围球内
    pub fn contains_point(&self, point: Vec3) -> bool {
        (point - self.center).length_squared() <= self.radius * self.radius
    }

    /// 检查两个包围球是否相交
    pub fn intersects(&self, other: &BoundingSphere) -> bool {
        let distance_squared = (self.center - other.center).length_squared();
        let radius_sum = self.radius + other.radius;
        distance_squared <= radius_sum * radius_sum
    }

    /// 合并两个包围球
    pub fn merge(&mut self, other: &BoundingSphere) {
        let direction = other.center - self.center;
        let distance = direction.length();

        // 如果一个球完全包含另一个球
        if distance + other.radius <= self.radius {
            return; // self 已经包含 other
        }
        if distance + self.radius <= other.radius {
            *self = *other; // other 包含 self，直接替换
            return;
        }

        // 计算新的中心和半径
        let new_radius = (self.radius + other.radius + distance) * 0.5;
        let new_center = if distance > 0.0 {
            self.center + direction * ((new_radius - self.radius) / distance)
        } else {
            self.center // 两个球心重合
        };

        self.center = new_center;
        self.radius = new_radius;
    }

    /// 使用变换矩阵变换包围球
    pub fn transform(&self, matrix: &Mat4) -> Self {
        // 计算变换后的中心
        let new_center = (*matrix * self.center.extend(1.0)).truncate();

        // 近似计算变换后的半径
        // 注意：这是一个保守的近似，实际半径可能更小
        let scale = matrix.to_scale_rotation_translation().0;
        let max_scale = scale.max_element();
        let new_radius = self.radius * max_scale;

        Self {
            center: new_center,
            radius: new_radius,
        }
    }
}
